package com.tool.cn.use.map;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.tool.cn.util.JsonUtil;

/**
 * 
 * @author wangzonghui
 * @date 2021-03-01 14:59:11
 * @Description 可续时Map，单位时间内未刷新，自动删除数据
 */
public final class ClearHashMap<T> {
	
	/**
	 * 辅助存储数据对象：key：key，value:存活秒数
	 */
	private  Map<String,Integer> keyMap=new HashMap<>();
	
	/**
	 * 数据存储对象：key:数据key  value：数据value
	 */
	private  Map<String,T> dataMap=new HashMap<>();
	
	
	/**
	 * 读写锁
	 */
	ReadWriteLock lock = new ReentrantReadWriteLock();

	private final Lock read = lock.readLock();    //读锁
    private final Lock write = lock.writeLock();    //写锁
    
	
	/**
	 * 构造方法
	 */
	public ClearHashMap(){
		keyMap=new HashMap<>();
		dataMap=new HashMap<>();
		TimerTask task=this.new clearTime();
		new Timer().schedule(task, new Date(), 1000); //一秒运行一次  
	}
	
	/**
	 * 获取值
	 */
	public T getDataValue(String key){
		
		read.lock();
		try {
			if(dataMap.containsKey(key)) {
				return dataMap.get(key);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			read.unlock();
		}
		return null;
	}
	
	/**
	 * 更新值
	 */
	public void updateDataValue(String key,T value){
		// 加写锁
        write.lock();
        
		try {
			if(dataMap.containsKey(key)) {
				dataMap.put(key, value);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			 // 释放写锁
            write.unlock();
		}
	}
	
	/**
	 * 添加永久存储值
	 * @param key key
	 * @param data value
	 */
	public void addData(String key,T data){
		addData(key,data, -1);
	}
	
	/**
	 * 添加数据，并设置时间
	 * @param data 数据
	 * @param second 时间，单位秒
	 */
	public void addData(String key,T data,int second){
		if(second<-1){
			System.out.println("数据存活时间必须不小于-1，等于-1永久存活");
			return;
		}
		
		 write.lock();
		try {
			keyMap.put(key, second);  //刷新数据存储时间
			dataMap.put(key, data);
			
			System.out.println("添加数据:"+key+"  "+data+"  keyMap:"+JsonUtil.toJson(keyMap)+" dataMap:"+JsonUtil.toJson(dataMap));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			 // 释放写锁
            write.unlock();
		}
	}
	
	/**
	 * 刷新数据时间
	 * @param key
	 * @param secode
	 */
	public void refreshData(String key,int second) {
		if(second<-1){
			System.out.println("数据存活时间必须不小于0，等于0永久存活");
			return;
		}
		
		 write.lock();
		try {
			keyMap.put(key, second);  //刷新数据存储时间
			
			System.out.println("添加数据:"+key+"  keyMap:"+JsonUtil.toJson(keyMap)+" dataMap:"+JsonUtil.toJson(dataMap));
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			 // 释放写锁
            write.unlock();
		}
	}
	
	private class clearTime extends TimerTask{

		@Override
		public void run() {

			if(keyMap.size()>0) {
				 lock.writeLock().lock();
				try {
					Integer value;
					String key;
					Iterator<Entry<String, Integer>> entries = keyMap.entrySet().iterator();
					while(entries.hasNext()){
					    Entry<String, Integer> entry = entries.next();
					    key = entry.getKey();
					    value = entry.getValue();
					    
					  //更新数据
						if(value==-1) {
							continue;
						}else if(value==0){  //删除数据
							if(keyMap.containsKey(key)) {
								entries.remove();;
							}
							
							if(dataMap.containsKey(key)) {
								dataMap.remove(key);
								System.out.println("~~~清空数据:"+key);
							}
							
						}else{
							value--;
							keyMap.put(key, value);
							
						}
						
						System.out.println("数据:"+key+"  keyMap:"+JsonUtil.toJson(keyMap)+" dataMap:"+JsonUtil.toJson(dataMap));
					}
					
				} catch (Exception e) {
					e.printStackTrace();
				}finally {
					 // 释放写锁
		            lock.writeLock().unlock();
				}
				
			}

		}
		
	}

	/**
	 * 验证key是否存在
	 * @param key
	 * @return
	 */
	public boolean containsKey(String key) {
		read.lock();
		try{
			return dataMap.containsKey(key);
		}finally {
			read.unlock();
		}
	}
}
